package main

import (
    "net/http"
    "os/exec"
    "encoding/json"
    "strings"
    "net"
    "os"
)

type ServerHandler struct {
}

type ResponseData struct {
    Success int          `json:"success"`
    Info    string       `json:"info"`
}

func sendResponse(w http.ResponseWriter, status int, ret *ResponseData) {
    w.Header().Set("Connection", "close")
    w.WriteHeader(status)
    buf, _ := json.Marshal(ret)
    w.Write([]byte(buf))
}

func checkUpdate() (int, string){
   
    cmd := "dnf check-upgrade | grep spice-gtk-tools | awk '{print $2}' | cut -d '.' -f 1,2";
    out, err := exec.Command("bash", "-c", cmd).Output()
    if err != nil {
        mainlog.Println("failed to run check-update: ", err)
        return 0, ""
    }
    if strings.Compare(string(out), "") == 0 {
        mainlog.Println("check-update get no new version")
        return 0, ""
    }
    return 1, string(out)
}

func startUpdate() {
    cmd := "dnf upgrade spice-glib spice-gtk3 spice-gtk-tools -y"
    out, err := exec.Command("bash", "-c", cmd).Output()
    if err != nil {
        mainlog.Println("failed to run update: ", err)
    }
    mainlog.Println(string(out))
}

func getVersion() (string, error) {
    cmd := "rpm -q  spice-gtk-tools |cut -d- -f 4,5|cut -d. -f 1,2"
    out, err := exec.Command("bash", "-c", cmd).Output()
    if err != nil {
        mainlog.Println("failed to get version: ", err)
        return "", err
    }
    return string(out), nil
}

func getMac() (string, error) {

    interfaces, err := net.InterfaceByName("eth0")
    if err != nil {
        mainlog.Println("failed to get mac: ", err)
        return "", err
    }

    mac := interfaces.HardwareAddr.String() //获取本机MAC地址
    mainlog.Println("MAC =", mac)
    return mac, nil
}

func (s *ServerHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    var ret ResponseData

    if req.URL.Path == "/check_update" && req.Method == "GET" {
        
        if result, new_version := checkUpdate(); result == 0 {
            ret.Info = "client has no new version"
        } else {
            ret.Info = "client has new version: " + new_version
            mainlog.Println(new_version);
        }
        ret.Success = 1
        sendResponse(w, 200, &ret)
        return
    }

    if req.URL.Path == "/do_update" && req.Method == "GET" {

        go startUpdate()

        ret.Success = 1
        ret.Info = "start update"
        sendResponse(w, 200, &ret)
        return
    }

    if req.URL.Path == "/get_version" && req.Method == "GET" {
    
        now_version, err := getVersion() 
        if err != nil {
            ret.Success = 0
            ret.Info = "there is no spicy in client"
            sendResponse(w, 404, &ret)
            return
        }
        mainlog.Println("now version:" + now_version)

        ret.Success = 1
        ret.Info = now_version
        sendResponse(w, 200, &ret)

        return
    }

    if req.URL.Path == "/do_state_check" && req.Method == "GET" {

        ret.Success = 1
        ret.Info = "network is ok"
        sendResponse(w, 200, &ret)

        return
    }

    if req.URL.Path == "/do_poweroff" && req.Method == "GET" {

        ret.Success = 1
        ret.Info = "poweroff is ok"
        sendResponse(w, 200, &ret)
        cmd := exec.Command("poweroff");
        cmd.Start();
        return
    }

    if req.URL.Path == "/do_reboot" && req.Method == "GET" {

        ret.Success = 1
        ret.Info = "reboot is ok"
        sendResponse(w, 200, &ret)
        cmd := exec.Command("reboot");
        cmd.Start();
        return
    }

    if req.URL.Path == "/get_mac" && req.Method == "GET" {

        mac, err := getMac()
        if err != nil {
            ret.Success = 0
            ret.Info = "get mac error"
            sendResponse(w, 404, &ret)
            return
        }
        ret.Success = 1
        ret.Info = mac
        sendResponse(w, 200, &ret)
 
        return
    }

    if req.URL.Path == "/get_hostname" && req.Method == "GET" {

        host, err := os.Hostname()
        if err != nil {
            ret.Success = 0
            ret.Info = "get hostname error"
            mainlog.Println("failed to get hostname: ", err)
            sendResponse(w, 404, &ret)
            return
        }

        ret.Success = 1
        ret.Info = host
        sendResponse(w, 200, &ret)
 
        return
    }

    if req.URL.Path == "/change_hostname" && req.Method == "POST" {

        req.ParseForm()
        param_hostname, hret := req.Form["hostname"]  
        if !hret {
            ret.Success = 0
            ret.Info = "change hostname error(use -d hostname=name)"
            mainlog.Println("failed to change hostname")
            sendResponse(w, 500, &ret)
            return
        }

        hname := param_hostname[0]  

        change_cmd := "hostnamectl set-hostname " + hname
        mainlog.Println(change_cmd)

        _, err := exec.Command("bash", "-c", change_cmd).Output()
        if err != nil {
            mainlog.Println("failed to run hostnamectl:", err)
            ret.Info = "change hostname error(failed to run hostnamectl)"
            sendResponse(w, 500, &ret)
            return
        }

        ret.Success = 1
        ret.Info = "change success"
        sendResponse(w, 200, &ret)
 
        return
    }

    ret.Success = 0
    ret.Info = "forbidden path or method"
    sendResponse(w, 403, &ret)
}

func initListen(listen string) {
    s := &http.Server {
        Addr: listen,
        Handler: &ServerHandler{},
    }
    mainlog.Println("start listen...");
	mainlog.Fatal(s.ListenAndServe())//ListenAndServe开启监听
}